<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>EasyPlayer.js播放器</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <script src="./js/easyplayer-pro.js"></script>
    <script src="./demo.js"></script>
</head>

<body>
    <div class="container">
        <div>
            <h5 class="text-lowercase text-bold">EasyPlayer.js播放器</h5>
        </div>
        <div class="mt-2">
            <div class="row">
                <div class="col-md-8">
                    <div id="video" style="background-color: black;aspect-ratio: 16 / 9;"></div>
                </div>
                <div class="col-md-4">
                    <p class="text-uppercase fw-bold">配置信息</p>
                    <div class="decoding row border-bottom mb-2 px-3">
                        <div class="form-check col">
                            <input class="form-check-input" type="checkbox" role="switch" id="useMSE" checked>
                            <label class="form-check-label" for="useMSE">MSE(硬解)</label>
                        </div>
                        <div class="form-check col">
                            <input class="form-check-input" type="checkbox" role="switch" id="useWCS">
                            <label class="form-check-label" for="useWCS">WCS(硬解)</label>
                        </div>
                        <div class="form-check col">
                            <input class="form-check-input" type="checkbox" role="switch" id="useSIMD">
                            <label class="form-check-label" for="useSIMD">WASM(软解)</label>
                        </div>
                    </div>
                    <div class="buffer row mb-2 border-bottom px-3">
                        <div class="form-check col-6">
                            <input class="form-check-input" type="checkbox" role="switch" id="networkDelayTimeoutReplay"
                                checked>
                            <label class="form-check-label" for="networkDelayTimeoutReplay">校时追帧</label>
                        </div>
                        <div class="form-check col-6">
                            <input class="form-check-input" type="checkbox" role="switch" id="replayUseLastFrameShow"
                                checked>
                            <label class="form-check-label" for="replayUseLastFrameShow">重播使用上一帧</label>
                        </div>
                        <div class="form-check col">
                            <input class="form-check-input" type="checkbox" role="switch" id="websocket1006ErrorReplay"
                                checked>
                            <label class="form-check-label" for="websocket1006ErrorReplay">WebSocket重连</label>
                        </div>
                        <div class="form-check col">
                            <input class="form-check-input" type="checkbox" role="switch" id="hasAudio" checked>
                            <label class="form-check-label" for="hasAudio">渲染音频</label>
                        </div>
                    </div>
                    <div class="mb-2 border-bottom">
                        <div class="form-group col-12 mb-2">
                            <label for="heartTimeout">超出时间无数据重连(s)</label>
                            <input type="text" class="form-control" id="heartTimeout" value="7" placeholder="如 3，5，7">
                        </div>
                        <div class="form-group col-12">
                            <label for="videoBufferDelay">达到延迟重播(s)</label>
                            <input type="text" class="form-control" id="videoBufferDelay" value="3"
                                placeholder="如 3，5，7">
                        </div>
                        <div class="form-group col-12">
                            <label for="fullscreenWatermarkConfig">水印</label>
                            <input type="text" class="form-control" id="fullscreenWatermarkConfig" value="EasyPlayer.js"
                                placeholder="如：3，5，7">
                        </div>
                        <div class="form-group col-12">
                            <label for="background">封面</label>
                            <input type="text" class="form-control" id="background" value=""
                                placeholder="如：https://xxx.png">
                        </div>
                        <div class="form-group col-12">
                            <label for="playHref">URL</label>
                            <input type="text" class="form-control" id="playHref"
                                value=""
                                placeholder="如：http://,https://,ws://,webrtc://">
                        </div>
                    </div>
                    <div class="mb-2 border-bottom">
                        <div>
                            <button type="button" class="btn btn-primary" id="play">播放</button>
                            <button type="button" class="btn btn-warning text-white" id="rePlay">重播</button>
                            <button type="button" class="btn btn-danger" id="destroy">销毁</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="mt-3">
            <h5>介绍：</h5>
            <div>1. 支持ws-flv, http-flv, hls, webrtc </div>
            <div class="text-warning">2. WebRTC使用方式：webrtc://xxx </div>
            <div>3. 使用时出现跨域请下载文件到本地调试</div>
            <div>4. 当浏览器不支持 MSE硬解 时，会自动切换成 WASM软解</div>
            <div>5. 关闭音频渲染可以节省性能</div>
            <div>6. 支持 电子放大; </div>
			<div>7. 支持 水印(动态水印、幽灵水印);</div>
			<div>8. 支持 显示上一个视频最后一帧;</div>
			<div>9. 支持 播放器快照截图;</div>
			<div>10.支持 视频录制(WebM格式(音频+视频)、MP4格式(视频),FLV格式(音频+视频));</div>
			<div>11.支持 超时、断网重连、异常暂停播放等;</div>
		</div>
        <div class="mt-3">
            <h5>属性配置</h5>
            <table class="table table-bordered">
                <thead class="thead-light">
                    <tr>
                        <th>属性</th>
                        <th>说明</th>
                        <th>类型</th>
                        <th>默认值</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>container</td>
                        <td>播放器容器</td>
                        <td>-</td>
                        <td>-</td>
                    </tr>
                    <tr>
                        <td>decoder</td>
                        <td>wasm解码地址</td>
                        <td>String</td>
                        <td>-</td>
                    </tr>
                    <tr>
                        <td>isResize</td>
                        <td>是否拉伸</td>
                        <td>Boolean</td>
                        <td>true</td>
                    </tr>
                    <tr>
                        <td>loadingText</td>
                        <td>加载显示的文字</td>
                        <td>String</td>
                        <td>加载中</td>
                    </tr>
                    <tr>
                        <td>videoBuffer</td>
                        <td>设置最小缓冲时长，单位秒，播放器会自动消除延迟</td>
                        <td>Number</td>
                        <td>1</td>
                    </tr>
                    <tr>
                        <td>hasAudio</td>
                        <td>是否解析音频</td>
                        <td>Boolean</td>
                        <td>true</td>
                    </tr>
                    <tr>
                        <td>useMSE</td>
                        <td>MSE模式</td>
                        <td>Boolean</td>
                        <td>false</td>
                    </tr>
                    <tr>
                        <td>useWCS</td>
                        <td>WCS模式</td>
                        <td>Boolean</td>
                        <td>false</td>
                    </tr>
                    <tr>
                        <td>useSIMD</td>
                        <td>强制使用wasm模式</td>
                        <td>Boolean</td>
                        <td>false</td>
                    </tr>
                    <tr>
                        <td>background</td>
                        <td>视频封面图片</td>
                        <td>String</td>
                        <td>-</td>
                    </tr>
                    <tr>
                        <td>qualityConfig</td>
                        <td>配置清晰度</td>
                        <td>Array</td>
                        <td>['普清', '高清', '超清', '4K', '8K']</td>
                    </tr>
                    <tr>
                        <td>defaultStreamQuality</td>
                        <td>默认显示的清晰度，如果不设置，会显示第一个清晰度</td>
                        <td>String</td>
                        <td>-</td>
                    </tr>
                    <tr>
                        <td>isNotMute</td>
                        <td>是否渲染音频</td>
                        <td>Boolean</td>
                        <td>false</td>
                    </tr>
                    <tr>
                        <td>recordType</td>
                        <td>视频录制默认mp4格式</td>
                        <td>String</td>
                        <td>mp4, flv</td>
                    </tr>
                    <tr>
                        <td>playbackForwardMaxRateDecodeIFrame</td>
                        <td>录像倍数</td>
                        <td>Number</td>
                        <td>-</td>
                    </tr>
                    <tr>
                        <td>debug</td>
                        <td>控制台日志打印</td>
                        <td>Boolean</td>
                        <td>false</td>
                    </tr>
                    <tr>
                        <td>debugLevel</td>
                        <td>打印日志级别默认warn</td>
                        <td>String</td>
                        <td>debug, warn</td>
                    </tr>
                </tbody>
            </table>

            <h5>调用方法和事件回调</h5>
            <table class="table table-bordered">
                <thead class="thead-light">
                    <tr>
                        <th>方法/事件</th>
                        <th>说明</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>play</td>
                        <td>播放</td>
                    </tr>
                    <tr>
                        <td>playback</td>
                        <td>播放录像</td>
                    </tr>
                    <tr>
                        <td>pause</td>
                        <td>暂停播放</td>
                    </tr>
                    <tr>
                        <td>isPause</td>
                        <td>返回是否暂停中状态</td>
                    </tr>
                    <tr>
                        <td>setBufferTime</td>
                        <td>设置最大缓冲时长</td>
                    </tr>
                    <tr>
                        <td>setVolume</td>
                        <td>设置音量</td>
                    </tr>
                    <tr>
                        <td>getVolume</td>
                        <td>获取音量</td>
                    </tr>
                    <tr>
                        <td>exitFullscreen</td>
                        <td>退出全屏(取消全屏)播放视频</td>
                    </tr>
                    <tr>
                        <td>mute</td>
                        <td>静音</td>
                    </tr>
                    <tr>
                        <td>cancelMute</td>
                        <td>取消静音</td>
                    </tr>
                    <tr>
                        <td>isMute</td>
                        <td>返回是否静音</td>
                    </tr>
                    <tr>
                        <td>screenshot</td>
                        <td>获取快照</td>
                    </tr>
                    <tr>
                        <td>setFullscreen</td>
                        <td>全屏</td>
                    </tr>
                    <tr>
                        <td>setStreamQuality</td>
                        <td>设置分辨率，必须是qualityConfig里面的数据</td>
                    </tr>
                    <tr>
                        <td>forward</td>
                        <td>设置录像倍数</td>
                    </tr>
                    <tr>
                        <td>setPlaybackStartTime</td>
                        <td>设置录像跳转时间/s</td>
                    </tr>
                    <tr>
                        <td>getVideoInfo</td>
                        <td>获取视频信息</td>
                    </tr>
                    <tr>
                        <td>getAudioInfo</td>
                        <td>获取音频信息</td>
                    </tr>
                    <tr>
                        <td>destroy</td>
                        <td>关闭视频，释放底层资源</td>
                    </tr>
                    <tr>
                        <td>play</td>
                        <td>播放事件</td>
                    </tr>
                    <tr>
                        <td>pause</td>
                        <td>暂停事件</td>
                    </tr>
                    <tr>
                        <td>videoInfo</td>
                        <td>视频信息</td>
                    </tr>
                    <tr>
                        <td>audioInfo</td>
                        <td>音频信息</td>
                    </tr>
                    <tr>
                        <td>mute</td>
                        <td>音频事件</td>
                    </tr>
                    <tr>
                        <td>error</td>
                        <td>播放异常</td>
                    </tr>
                    <tr>
                        <td>kBps</td>
                        <td>当前网速，单位KB 每秒1次</td>
                    </tr>
                    <tr>
                        <td>recordEnd</td>
                        <td>录制结束的事件</td>
                    </tr>
                    <tr>
                        <td>recordStart</td>
                        <td>录制开始的事件</td>
                    </tr>
                    <tr>
                        <td>fullscreen</td>
                        <td>当前是否全屏</td>
                    </tr>
                    <tr>
                        <td>streamQualityChange</td>
                        <td>清晰度回调</td>
                    </tr>
                    <tr>
                        <td>playbackSeek</td>
                        <td>录像时间轴跳转回调</td>
                    </tr>
                    <tr>
                        <td>playbackPreRateChange</td>
                        <td>录像倍数的回调</td>
                    </tr>
                    <tr>
                        <td>currentPts</td>
                        <td>监听当前渲染帧的时间戳（流里面的）</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
        crossorigin="anonymous"></script>
    <script>
        var easypro;
        var $player = document.getElementById('play');
        var $destroy = document.getElementById('destroy');
        var $rePlay = document.getElementById('rePlay');
        var $playHref = document.getElementById('playHref');
        var $container = document.querySelector('#video');
        var $videoBufferDelay = document.querySelector('#videoBufferDelay');
        var $useMSE = document.querySelector('#useMSE');
        var $useWCS = document.querySelector('#useWCS');
        var $useSIMD = document.querySelector('#useSIMD');
        var $hasAudio = document.querySelector('#hasAudio');
        var $isNakedFlow = document.querySelector('#isNakedFlow');
        var $websocket1006ErrorReplay = document.querySelector('#websocket1006ErrorReplay');
        var $networkDelayTimeoutReplay = document.querySelector('#networkDelayTimeoutReplay');
        var $heartTimeout = document.querySelector('#heartTimeout');
        var $replayUseLastFrameShow = document.querySelector('#replayUseLastFrameShow');
        var $fullscreenWatermarkConfig = document.querySelector('#fullscreenWatermarkConfig');
        var $background = document.querySelector('#background');
        function create(options) {
            options = options || {}

            easypro = new EasyPlayerPro({
                container: $container,
                videoBuffer: 0.2, // 缓存时长
                videoBufferDelay: Number($videoBufferDelay.value), // 1000s
                decoder: './js/decoder-pro.js',
                isResize: false,
                text: "",
                loadingText: "加载中", debug: true,
                debugLevel: "debug",
                useMSE: $useMSE.checked === true,
                useSIMD: $useSIMD.checked === true,
                useWCS: $useWCS.checked === true,
                hasAudio: $hasAudio.checked === true,
                websocket1006ErrorReplay: $websocket1006ErrorReplay.checked === true,
                networkDelayTimeoutReplay: $networkDelayTimeoutReplay.checked === true,
                useMThreading: true,
                showBandwidth: true, // 显示网速
                showPerformance: true, // 显示性能
                operateBtns: {
                    fullscreen: true,
                    screenshot: true,
                    play: true,
                    audio: true,
                    ptz: true,
                    quality: true,
                    performance: true,
                    screenshotFn: screenshotFn,
                },
                background: $background.value,
                timeout: 10,
                qualityConfig: ['普清', '高清', '超清', '4K', '8K'],
                forceNoOffscreen: true,
                isNotMute: false,
                heartTimeout: Number($heartTimeout.value),
                ptzClickType: 'mouseDownAndUp',
                ptzZoomShow: true,
                ptzMoreArrowShow: true,
                ptzApertureShow: true,
                ptzFocusShow: true,
                pauseAndNextPlayUseLastFrameShow: $replayUseLastFrameShow.checked === true,
                heartTimeoutReplayUseLastFrameShow: $replayUseLastFrameShow.checked === true,
                replayUseLastFrameShow: $replayUseLastFrameShow.checked === true, // 重播使用上一帧显示
                fullscreenWatermarkConfig: {
                    text: $fullscreenWatermarkConfig.value,
                }
            });
        }

        const screenshotFn = () => {
            if (easypro) {
                easypro.screenshotWatermark({
                    text: {
                        content: `${$fullscreenWatermarkConfig.value}`,
                        fontSize: '46',
                        color: 'rgba(100,100,100,.6)',
                    },
                    opacity: 0.8,
                    right: 20,
                    top: 50,
                });
            }
        };

        create();


        easypro.on('streamQualityChange', (value) => {
            console.log('streamQualityChange', value);
        })

        easypro.on('timeUpdate', (value) => {
            // console.log('timeUpdate', value);
        })

        easypro.on('stats', (stats) => {
            // console.log('stats', stats);
        })

        easypro.on('error', (errorType, message) => {
            console.error('error', errorType, message);
        })

        easypro.on('crashLog', (info) => {
            console.error('crashLog', info);
        })

        easypro.on('playFailedAndPaused', (reason, lastFrameInfo, msg) => {
            console.error('playFailedAndPaused', reason, lastFrameInfo, msg);
        });


        function play() {
            var href = $playHref.value;
            if (href) {
                easypro.play(href);
            } else {
                easypro.showErrorMessageTips('播放地址不能为空');
            }
        }


        function replay(options) {
            if (easypro) {
                easypro.destroy().then(() => {
                    create(options);
                    play();
                });
            } else {
                create();
                play();
            }
        }

        $player.addEventListener('click', function () {
            play();
        }, false)


        $destroy.addEventListener('click', function () {
            if (easypro) {
                easypro.destroy().then(() => {
                    create();
                });
            } else {
                create();
            }

        })

        $useMSE.addEventListener('change', function () {
            replay();
        })

        $useSIMD.addEventListener('change', function () {
            replay();
        })

        $useWCS.addEventListener('change', function () {
            replay();
        })

        $hasAudio.addEventListener('change', function () {
            replay();
        })


        $websocket1006ErrorReplay.addEventListener('change', function () {
            replay();
        })

        $rePlay.addEventListener('click', function () {
            replay();
        })
        $background.addEventListener('change', function () {
            if (easypro) {
                easypro.destroy().then(() => {
                    create();
                });
            } else {
                create();
            }
        })

        $networkDelayTimeoutReplay.addEventListener('change', function () {
            replay();
        })
    </script>
</body>

</html>